<style lang="less" scoped>
  @import (reference) "../../assets/styles/common.less";
  .line-field {
    legend {
      font-weight: 800;
    }
  }

  .keyframes (enter-bounce, {
      0% {
        .transform(scale(0));
        background-color: rgba(250, 220, 174, 0.87);
      }
      50% {
        .transform(scale(1.2));
      }
      100% {
        .transform(scale(1));
        background-color: inherit;
      }
  });

  /* 可以设置不同的进入和离开动画 */
  /* 设置持续时间和动画函数 */
  .list-complete {
    &-enter {
      &-active {
        .animation(enter-bounce, 1.2s, ease, 0s, 1, normal, forwards);
      }
    }
  }

  .form-container {
    .link-wrapper {
      position: fixed;
      top: 150px;
      right: 45px;
      width: 125px;
    }

    .ivu-divider-dashed {
      border-color: #ccc;
      padding-top: 20px;
    }
  }

  #edit-modal .ivu-modal-body .form-container .link-wrapper {
    top: 165px;
    right: 62px;
  }
</style>

<template>
  <div class="form-container">
    <div class="link-wrapper">
      <Anchor
        :affix="false"
        :offset-top="200"
        :scroll-offset="-110"
        :container="scrollContainer"
        show-ink>
        <AnchorLink href="#course_info" :scroll-offset="110" title="课程基本信息"/>
        <AnchorLink href="#exp_info" title="实验基本信息">
          <AnchorLink
            v-for="(expBaseInfoItem, expBaseInfoIndex) in applyTraining.expBaseInfoItems"
            :key="expBaseInfoItem.guid"
            :href="`#exp_item_${expBaseInfoIndex + 1}`"
            :title="`实验${expBaseInfoIndex + 1}`" />
        </AnchorLink>
        <AnchorLink href="#actions" title="提交 / 重置" />
      </Anchor>
    </div>
    <div class="form-wrapper">
      <Form
        ref="applyTraining"
        :model="applyTraining"
        :rules="ruleValidate"
        :label-position="labelPosition"
        :label-width="labelWidth"
        style="width: calc(100% - 150px)">
        <fieldset class="line-field" id="course_info">
          <legend>课程基本信息</legend>
          <FormItem label="所属学院" prop="institute">
            <Select
                v-model="applyTraining.institute"
                filterable
                :disabled="!userAccess.some(item => { return ['ROLE_SCHOOL_ADMIN', 'ROLE_ROOT'].indexOf(item) > -1 }) || isModified"
                v-if="userAccess.some(item => { return ['ROLE_SCHOOL_ADMIN', 'ROLE_ROOT'].indexOf(item) > -1 }) && !isModified"
                :enabledPreventOverflow="enabledPreventOverflow"
                :not-found-text="loading.institute ? '查询学院中，请稍等...' : '无可选学院'"
                @on-change="onSelectInstitute"
                placeholder="请先选择学院">
                <Option v-for="(option, index) in options.institute" :value="option" :key="index">{{option}}</Option>
            </Select>
            <Input v-else v-model="applyTraining.institute" readonly placeholder="教师所属学院" />
          </FormItem>
          <FormItem label="教师姓名" prop="teacher_name">
            <Input v-model="applyTraining.teacher_name" :readonly="!userAccess.some(item => { return ['ROLE_ROOT', 'ROLE_SCHOOL_ADMIN', 'ROLE_INSTITUTE_ADMIN'].indexOf(item) > -1 }) || isModified" prefix="ios-contact" placeholder="请输入教师姓名" />
          </FormItem>
          <FormItem label="课程" prop="course_name">
            <Input v-model="applyTraining.course_name" :readonly="isModified" prefix="ios-book-outline" placeholder="请输入课程名称" />
          </FormItem>
          <FormItem label="实验教材" prop="textbook">
            <Input type="textarea" v-model="applyTraining.textbook" placeholder="实验指导书名称，编(写)者，出版社，出版日期" clearable :autosize="{minRows: 2, maxRows: 6}"></Input>
          </FormItem>
          <FormItem label="实训对象" class="ivu-form-item-required">
            <Row :gutter="20" type="flex" justify="space-between" style="margin-bottom: 15px;"
              v-for="(classesItem, classesIndex) in applyTraining.classes"
              :key="classesItem.guid">
              <Col span="2" class="pl-15">年级：</Col>
              <Col span="5">
                <FormItem :prop="'classes.' + classesIndex + '.grade'" :rules="ruleValidate.grade">
                  <Select :enabledPreventOverflow="enabledPreventOverflow" v-model="classesItem.grade"
                          placeholder="请选择年级" filterable @on-change="onChangeGrade(classesIndex)">
                    <Option v-for="option in options.grade" :value="option" :key="option">{{ option }}</Option>
                  </Select>
                </FormItem>
              </Col>
              <Col span="2" class="pl-15">专业：</Col>
              <Col span="7">
                <FormItem :prop="'classes.' + classesIndex + '.major'" :rules="ruleValidate.major">
                  <Select :enabledPreventOverflow="enabledPreventOverflow"
                          v-model="classesItem.major"
                          :placeholder="isFillInstitute ? (classesItem.grade ? '请选择专业' : '请先选择年级') : '请先选择学院'"
                          filterable clearable
                          :not-found-text="classesItem.major_loading ? '查询专业中，请稍等...' : '无可选专业'"
                          :disabled="!(isFillInstitute && classesItem.grade)">
                    <Option v-for="option in classesItem.major_options" :value="option" :key="option">{{ option }}</Option>
                  </Select>
                </FormItem>
              </Col>
              <Col span="7" class="text-right">
                <Poptip
                    confirm
                    title="确认删除该实训对象吗？"
                    @on-ok="remove_teach_obj(classesIndex)"
                    v-if="!(classesIndex === 0 && applyTraining.classes.length === 1)"
                    :options="popperOpts"
                    class="text-left">
                  <Tooltip content="删除该实训对象">
                    <Button type="warning" shape="circle" icon="md-trash"></Button>
                  </Tooltip>
                </Poptip>
                <Tooltip content="新增实训对象"
                        v-if="classesIndex + 1 === applyTraining.classes.length"
                        style="margin-left: 1.5em">
                  <Button type="info" shape="circle" icon="md-add"
                          @click="add_teach_obj"></Button>
                </Tooltip>
              </Col>
            </Row>
            <Alert v-if="error.teach_object" show-icon type="error">{{ error.teach_object }}</Alert>
          </FormItem>
          <FormItem label="人数" prop="stu_num">
              <InputNumber :min="1" v-model="applyTraining.stu_num" placeholder="总人数" style="width: 220px"></InputNumber>
          </FormItem>
        </fieldset>
        <div v-if="!historyLoading">
          <transition-group name="list-complete" tag="div" id="exp_info" @leave="leave">
            <fieldset
                class="line-field list-complete-item"
                v-for="(expBaseInfoItem, expBaseInfoIndex) in applyTraining.expBaseInfoItems"
                ref="baseInfoRef"
                :key="expBaseInfoItem.guid"
                :id="`exp_item_${expBaseInfoIndex + 1}`">
                <legend>实训项目{{ expBaseInfoIndex + 1 }} 基本信息</legend>
                <FormItem label="基本信息" class="ivu-form-item-required">
                  <Row :gutter="20" type="flex" justify="space-around">
                    <Col span="2" class="pl-15">编号：</Col>
                    <Col span="5">
                      <FormItem>
                        <Input disabled placeholder="项目编号" :value="(expBaseInfoIndex + 1)" style="width: 100%"></Input>
                      </FormItem>
                    </Col>
                    <Col span="2" class="pl-15">类型：</Col>
                    <Col span="6">
                      <FormItem :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.type'" :rules="ruleValidate.type">
                        <Select :enabledPreventOverflow="enabledPreventOverflow" v-model="expBaseInfoItem.type" placeholder="实验类型">
                          <Option value="验证性">验证性</Option>
                          <Option value="演示性">演示性</Option>
                          <Option value="练习性">练习性</Option>
                          <Option value="创新性">创新性</Option>
                          <Option value="设计性">设计性</Option>
                          <Option value="综合性">综合性</Option>
                          <Option value="其他">其他</Option>
                        </Select>
                      </FormItem>
                    </Col>
                    <Col span="2" class="pl-15">学时：</Col>
                    <Col span="6">
                      <FormItem :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.learntime'" :rules="ruleValidate.learntime">
                        <InputNumber :min="1" v-model="expBaseInfoItem.learntime" style="width: 100%"
                                     placeholder="计划学时"></InputNumber>
                      </FormItem>
                    </Col>
                  </Row>
                </FormItem>
                <FormItem label="项目名称" :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.title'" :rules="ruleValidate.title">
                  <Input v-model="expBaseInfoItem.title" clearable placeholder="请输入实验项目名称"></Input>
                </FormItem>
                <FormItem label="耗材需求" :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.resources'"
                          :rules="ruleValidate.resources">
                  <Input type="textarea" v-model="expBaseInfoItem.resources" clearable @on-blur="blur_need('resources', expBaseInfoIndex)" placeholder="本次实验的耗材需求"></Input>
                </FormItem>
                <FormItem label="系统需求" :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.system'" :rules="ruleValidate.system">
                  <Input type="textarea" v-model="expBaseInfoItem.system" clearable @on-blur="blur_need('system', expBaseInfoIndex)" placeholder="本次实验的系统需求"></Input>
                </FormItem>
                <FormItem label="软件需求" :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.software'"
                          :rules="ruleValidate.software">
                  <Input type="textarea" v-model="expBaseInfoItem.software" clearable @on-blur="blur_need('software', expBaseInfoIndex)" placeholder="本次实验的软件需求"></Input>
                </FormItem>
                <FormItem
                  label="时间及实验室"
                  v-for="(timeItem, expTimeIndex) in expBaseInfoItem.expTimeItems"
                  :key="timeItem.guid"
                  class="ivu-form-item-required ivu-divider-dashed">
                  <Row :gutter="20" type="flex" justify="start">
                    <Col span="3" class="pl-15">时间：</Col>
                    <Col span="7">
                      <FormItem
                        :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.expTimeItems.' + expTimeIndex + '.date'"
                        :rules="ruleValidate.date">
                        <DatePicker
                          :value="timeItem.date"
                          format="yyyy-MM-dd"
                          type="daterange"
                          confirm
                          clearable
                          :options="datePickerOpts"
                          :enabledPreventOverflow="enabledPreventOverflow"
                          placeholder="请选择实验时间"
                          @on-change="changeExpDate(timeItem, $event)"
                          style="width: 100%;"></DatePicker>
                      </FormItem>
                    </Col>
                    <Col span="14" class="pl-15">
                      <span class="mr-10">周末是否上课：</span>
                      <i-switch v-model="timeItem.haveClassOnWeekend" size="small" @on-change="onChangeHaveClassSwitch(timeItem)" :disabled="isWeekend(timeItem.date)">
                      </i-switch>
                      <span style="color: #b9b9b9;margin-left: 10px;">{{ timeItem.haveClassOnWeekend ? isWeekend(timeItem.date) ? '当前所选时间为周末，此处必选为上课' : '( 上课 )' : '( 不上课 )'}}</span>
                    </Col>
                  </Row>
                  <br>
                  <Row :gutter="20" type="flex" justify="space-between">
                    <Col span="3" class="pl-15 pr-0">学院：</Col>
                    <Col span="12">
                      <FormItem :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.expTimeItems.' + expTimeIndex + '.institute'"
                              :rules="ruleValidate.institute">
                        <Select v-model="timeItem.institute"
                                :enabledPreventOverflow="enabledPreventOverflow"
                                placeholder="请选择实验室所属学院"
                                filterable
                                :not-found-text="loading.institute ? '查询学院中，请稍等...' : '无可选学院'"
                                @on-change="changeExpDate(timeItem, $event)">
                          <Option v-for="(option, index) in options.institute" :value="option" :key="index">{{ option }}</Option>
                        </Select>
                      </FormItem>
                    </Col>
                    <Col span="8" offset="1"></Col>
                  </Row>
                  <br>
                  <Row :gutter="20" type="flex" justify="space-between">
                    <Col span="3" class="pl-15 pr-0">实验室：</Col>
                    <Col span="12">
                      <FormItem
                        :prop="'expBaseInfoItems.' + expBaseInfoIndex + '.expTimeItems.' + expTimeIndex + '.classroom'"
                        :rules="ruleValidate.classroom">
                        <Select
                          v-model="timeItem.classroom"
                          :enabledPreventOverflow="enabledPreventOverflow"
                          :disabled="!(timeItem.institute && timeItem.date.length > 0 && timeItem.date[0] !== '' && timeItem.date[1] !== '')"
                          :placeholder="timeItem.institute ? (timeItem.date.length > 0 && timeItem.date[0] !== '' && timeItem.date[1] !== '' ? '请选择实验室' : '请先选择实验时间') : '请先选择学院'"
                          :not-found-text="timeItem.labLoading ? '查询实验室中，请稍等...' : '无可选实验室'"
                          multiple>
                          <Option
                            v-for="item in applyTraining.expBaseInfoItems[expBaseInfoIndex].expTimeItems[expTimeIndex].laboratoryList"
                            :label="item.code"
                            :value="item.code"
                            :key="item.code"
                            :disabled="!('ACTIVATING'===item.status)">
                            <span>{{ item.code }}</span>
                            <span style="float:right;color:#ccc;margin-right: 15px;">{{ item.name + ' (' + item.capacity + '人)' }}</span>
                          </Option>
                        </Select>
                      </FormItem>
                    </Col>
                    <Col span="8" offset="1" class="text-right">
                      <Poptip
                        confirm
                        title="确认删除该实验时间吗？"
                        @on-ok="remove_time(expBaseInfoItem, timeItem, expTimeIndex)"
                        v-if="!(expTimeIndex === 0 && expBaseInfoItem.expTimeItems.length === 1)"
                        :options="popperOpts"
                        class="text-left">
                        <Tooltip content="删除该实验时间">
                          <Button type="warning" shape="circle" icon="md-trash"></Button>
                        </Tooltip>
                      </Poptip>
                      <Tooltip content="新增实验时间"
                               v-if="expTimeIndex + 1 === expBaseInfoItem.expTimeItems.length"
                               style="margin-left: 1.5em">
                        <Button type="info" shape="circle" icon="md-add"
                                @click="add_time(expBaseInfoItem.expTimeItems)"></Button>
                      </Tooltip>
                    </Col>
                  </Row>
                </FormItem>
                <div class="text-right position-relative ivu-divider-dashed">
                  <Poptip
                    confirm
                    :title="'确认删除实验' + (expBaseInfoIndex + 1) + '吗?'"
                    @on-ok="remove_exp_info(expBaseInfoItem, expBaseInfoIndex)"
                    v-if="!(expBaseInfoIndex === 0 && applyTraining.expBaseInfoItems.length === 1)"
                    class="text-left"
                    :options="popperOpts">
                    <Button type="warning" icon="ios-close-circle-outline">删除实验{{ expBaseInfoIndex + 1 }}</Button>
                  </Poptip>
                  <Button type="primary" icon="md-add"
                          @click="add_exp_info"
                          v-if="expBaseInfoIndex + 1 === applyTraining.expBaseInfoItems.length"
                          style="margin-left: 1.5em">
                    增加到实验{{ expBaseInfoIndex + 2 }}
                  </Button>
                </div>
              </fieldset>
          </transition-group>
        </div>
      </Form>
    </div>
    <Modal v-model="modal.show" width="550" @on-ok="modal.show = false" @on-cancel="modal.show = false">
      <p slot="header" class="text-center" style="color:#f60;">
        <Icon type="ios-information-circle"></Icon>
        <span>{{ modal.title }}</span>
      </p>
      <div>
        <Table height="300" border size="small" :columns="occupyColumns" :data="occupyData"></Table>
      </div>
    </Modal>
  </div>
</template>
<script>
import Velocity from 'velocity-animate'
import { editApply, getInstituteList, getLabByDates, getMajorByGradeAndInstitute, submitApply } from '@/api/apply-form'
import { generateGuid } from '@/libs/tools'
import { mapActions } from 'vuex'
export default {
  name: 'ApplyTraining',
  data () {
    const validateExpDate = (rule, value, callback) => {
      if (value && value[0] && value[1]) {
        callback()
      } else {
        callback(new Error('请选择实验时间'))
      }
    }
    return {
      userAccess: [],
      scrollContainer: '',
      historyLoading: false,
      isFilledFormByData: false,
      timer: '',
      options: {
        grade: [],
        major: [],
        institute: []
      },
      loading: {
        major: false,
        submit: false,
        institute: true
      },
      error: {
        teach_object: null
      },
      /* 利用MutationObserver实现监听元素class的变化 */
      observers: null,
      applyTraining: {
        exp_type: 'TRAINING',
        institute: null,
        teacher_name: null,
        course_name: null,
        textbook: null,
        classes: [{
          guid: generateGuid(),
          grade: null,
          major: null,
          major_options: [],
          major_loading: false
        }],
        stu_num: null,
        expBaseInfoItems: [
          {
            guid: generateGuid(),
            sid: 1,
            type: null,
            title: null,
            learntime: null,
            resources: null,
            system: null,
            software: null,
            expTimeItems: [
              {
                guid: generateGuid(),
                institute: '',
                date: ['', ''],
                haveClassOnWeekend: false,
                classroom: [],
                laboratoryList: [],
                labLoading: false
              }
            ]
          }
        ]
      },
      ruleValidate: {
        institute: [
          {required: true, message: '学院不能为空', trigger: 'change'}
        ],
        teacher_name: [
          {required: true, message: '教师不能为空', trigger: 'blur'}
        ],
        course_name: [
          {required: true, message: '课程名字不能为空', trigger: 'blur'}
        ],
        grade: [
          {required: true, type: 'number', message: '年级不能为空', trigger: 'change'}
        ],
        major: [
          {required: true, message: '专业不能为空', trigger: 'change'}
        ],
        textbook: [
          {required: true, message: '实验教材详细情况不能为空', trigger: 'blur'}
        ],
        classroom: [
          {required: true, type: 'array', message: '实验室不能为空', trigger: 'change'}
        ],
        classes: [
          {required: true, type: 'array', min: 1, message: '至少选择一个班级', trigger: 'change'}
        ],
        stu_num: [
          {required: true, type: 'number', message: '人数不能为空', trigger: 'change'},
          {required: true, type: 'number', message: '人数不能为空', trigger: 'blur'}
        ],
        type: [
          {required: true, message: '实验类型不能为空', trigger: 'change'}
        ],
        title: [
          {required: true, message: '实验项目不能为空', trigger: 'blur'}
        ],
        date: [
          { validator: validateExpDate, trigger: 'change' }
        ],
        learntime: [
          {required: true, type: 'number', message: '学时不能为空', trigger: 'change'},
          {required: true, type: 'number', message: '学时不能为空', trigger: 'blur'}
        ],
        resources: [
          {required: true, message: '耗材需求不能为空', trigger: 'blur'}
        ],
        system: [
          {required: true, message: '系统需求不能为空', trigger: 'blur'}
        ],
        software: [
          {required: true, message: '软件需求不能为空', trigger: 'blur'}
        ]
      },
      labelPosition: 'left',
      labelWidth: 100,
      // Select选择器和DatePicker日期选择器的下拉列表是否吸附，默认为true，吸附
      enabledPreventOverflow: false,
      popperOpts: {
        modifiers: {
          preventOverflow: {
            // 边界元素: scrollParent, window, viewport or any DOM element. 默认iview默认window
            boundariesElement: 'scrollParent'
          }
        }
      },
      datePickerOpts: {
        disabledDate (date) {
          return date && date.valueOf() < Date.now() - 86400000
        }
      },
      occupyColumns: [
        {
          title: '实验编号',
          key: 'expIndex',
          sortable: true,
          width: 110
        },
        {
          title: '日期',
          key: 'date',
          sortable: true,
          width: 130
        },
        {
          title: '实验室',
          key: 'code'
        }
      ],
      occupyData: [],
      modal: {
        show: false,
        title: '抱歉，提交失败，实验室使用时间冲突'
      }
    }
  },
  props: {
    interactiveData: {
      type: Object
    },
    pdfData: {
      type: Object
    },
    isModified: {
      type: Boolean,
      default: false
    }
  },
  created: function () {
    let history = null
    if (this.isModified) {
      this.showSpinWithTip('加载表单数据中，请稍等...')
    } else {
      // 当有localstorage不为空时才显示加载历史记录
      if (localStorage.getItem('applyTraining')) {
        this.showSpinWithTip('加载历史数据中，请稍等...')
        history = {
          string: localStorage.getItem('applyTraining'),
          json: JSON.parse(localStorage.getItem('applyTraining'))
        }
      }
    }

    // 获取当前登录的用户信息
    this.getUserInfo().then(response => {
      let res = response.data
      if (res.code === 1) {
        let name = this.$store.state.user.userName // 教师姓名
        let access = this.userAccess = this.$store.state.user.access // 教师权限
        let institute = this.$store.state.user.department || '' // 所属学院
        getInstituteList().then(response => {
          let res = response.data
          this.options.institute = []
          this.loading.institute = false
          if (res.code) {
            this.options.institute = res.data
          } else {
            this.$Notice.error({
              title: '获取学院列表失败',
              desc: res.info
            })
          }
          if ((this.isModified && this.isFilledFormByData) || !this.isModified) {
            this.$nextTick(() => {
              this.$Spin.hide()
            })
          }
        }).catch(error => {
          console.log(error)
          this.loading.institute = false
          this.$Spin.hide()
          this.$Notice.error({
            title: '获取学院列表失败',
            desc: error
          })
        })
        if (access.some(item => { return ['ROLE_ROOT', 'ROLE_SCHOOL_ADMIN', 'ROLE_INSTITUTE_ADMIN'].indexOf(item) > -1 })) {
          if (history) {
            // 当有localstorage时才赋值旧数据
            this.historyLoading = true
            this.applyTraining = history.json
            this.$nextTick(() => {
              this.historyLoading = false
            })
          } else {
            this.applyTraining.teacher_name = name
            this.applyTraining.institute = this.applyTraining.expBaseInfoItems[0].expTimeItems[0].institute = institute
          }
          if ((this.isModified && this.isFilledFormByData) || !this.isModified) {
            this.$nextTick(() => {
              this.$Spin.hide()
            })
          }
        } else {
          if (history && history.json.teacher_name === name) {
            // 如果localstorage的旧数据不是当前登录教师的，则不赋值
            this.historyLoading = true
            this.options.institute.push(institute)
            this.applyTraining = history.json
            this.$nextTick(() => {
              this.historyLoading = false
            })
          } else {
            this.applyTraining.teacher_name = name
            // this.options.institute.push(institute)
            this.applyTraining.institute = this.applyTraining.expBaseInfoItems[0].expTimeItems[0].institute = institute
          }
          if ((this.isModified && this.isFilledFormByData) || !this.isModified) {
            this.$nextTick(() => {
              this.$Spin.hide()
            })
          }
        }
      } else {
        this.$nextTick(() => {
          this.$Spin.hide()
        })
        this.$Notice.error({
          title: '提示',
          desc: '获取用户信息失败！' + res.info
        })
      }
    }).catch(error => {
      console.log(error)
      this.$Notice.error({
        title: '提示',
        desc: '获取用户信息失败！'
      })
      this.$nextTick(() => {
        this.$Spin.hide()
      })
    })
    this.getCurrentGrades(new Date())
  },
  mounted: function () {
    this.$Notice.config({
      top: window.innerHeight / 3,
      duration: 3
    })
    this.scrollContainer = this.isModified ? document.querySelector('#edit-modal .ivu-modal-wrap') : document.querySelector('.content-wrapper.ivu-layout-content')
    this.startMutationObserver()
  },
  beforeDestroy () {
    this.$Notice.destroy()
    /* 利用MutationObserver实现监听元素class的变化 */
    if (this.observer) {
      this.observer.disconnect()
      this.observer.takeRecords()
      this.observer = null
    }
  },
  methods: {
    ...mapActions([
      'getUserInfo'
    ]),
    getCurrentGrades (date = new Date()) {
      // getYear获取的时间如果小于1900,那就要加上1900
      // 比如 2017 ,getYear获取的时间就是117,加上1900就是2017
      let current = {
        year: (date.getYear() < 1900) ? (1900 + date.getYear()) : date.getYear(),
        month: date.getMonth() + 1
      }
      if (current.month < 8) {
        this.options.grade = [
          current.year - 4,
          current.year - 3,
          current.year - 2,
          current.year - 1
        ]
      } else {
        this.options.grade = [
          current.year - 3,
          current.year - 2,
          current.year - 1,
          current.year - 0
        ]
      }
    },
    // 当“耗材、系统、软件需求”失去焦点时，把当前值填充到其余实验项目空的需求值上
    blur_need (type, baseIndex) {
      let baseItems = this.applyTraining.expBaseInfoItems
      const need = {
        'resources': baseItems[baseIndex].resources,
        'system': baseItems[baseIndex].system,
        'software': baseItems[baseIndex].software
      }
      let val = need[type]
      if (val) {
        baseItems.forEach((item, index) => {
          if (item[type] === null || item[type] === '') {
            item[type] = val
          }
        })
      }
    },
    // 获取学院列表
    getInstitute () {
      getInstituteList().then(response => {
        let res = response.data
        this.options.institute = res
        if (res.code === 1) {
          this.options.institute = res.data
        } else {
          this.$Notice.error({
            title: '获取学院列表失败',
            desc: res.info
          })
        }
        return res
      }).catch(error => {
        this.options.institute = []
        console.log(error)
        return null
      })
    },
    // 改变学院值的回调函数
    async onSelectInstitute (value) {
      if (value) {
        let classes = this.applyTraining.classes
        for (let i = 0; i < classes.length; i++) {
          // 获取已选年级那一栏的专业列表
          if (classes[i].grade) {
            classes[i].major = ''
            classes[i].major_options = await this.getMajorOptions(classes[i])
          }
        }
      }
    },
    // 改变年级的回调函数
    async onChangeGrade (index) {
      let classItem = this.applyTraining.classes[index]
      let institute = this.applyTraining.institute
      classItem.major = ''
      if (institute && classItem.grade) {
        classItem.major_options = await this.getMajorOptions(classItem)
        if (classItem.major_options.length < 1) {
          this.$Notice.error({
            title: '抱歉',
            desc: classItem.grade + '级' + this.applyTraining.institute + '下暂无专业，请选择其他年级。'
          })
        }
      }
    },
    // 获取专业列表
    async getMajorOptions (item) {
      item.major_options = []
      item.major_loading = true
      let grade = item.grade
      let institute = this.applyTraining.institute
      try {
        let res = await getMajorByGradeAndInstitute(grade, institute)
        res = res.data
        item.major_loading = false
        if (res.code && res.data.length > 0) {
          return res.data
        } else {
          return []
        }
      } catch (error) {
        item.major_loading = false
        return []
      }
    },
    // 增加实训对象
    add_teach_obj (value) {
      this.applyTraining.classes.push({
        guid: generateGuid(),
        grade: null,
        major: null,
        major_options: []
      })
    },
    // 删除实训对象
    remove_teach_obj (index) {
      this.applyTraining.classes.splice(index, 1)
    },
    // 新增实验时间
    add_time (item) {
      item.push({
        guid: generateGuid(),
        institute: this.applyTraining.expBaseInfoItems[0].expTimeItems[0].institute,
        date: ['', ''],
        haveClassOnWeekend: false,
        classroom: [],
        laboratoryList: [],
        labLoading: false
      })
    },
    // 删除实验时间
    remove_time (expBaseInfoItem, item, index) {
      if (expBaseInfoItem.expTimeItems.indexOf(item) !== -1) {
        expBaseInfoItem.expTimeItems.splice(index, 1)
      }
    },
    // 改变实训项目时间回调函数
    async changeExpDate (item, value) {
      item.classroom = []
      if (this.getElClass(value) === 'Array') {
        item.date = value
        if (this.isWeekend(value)) {
          item.haveClassOnWeekend = true
        }
      }
      let institute = item.institute
      if (institute && item.date.length > 0 && item.date[0] !== '' && item.date[1] !== '') {
        try {
          item.laboratoryList = []
          item.labLoading = true
          item.laboratoryList = await this.getLabOptions(item)
          item.classroom = []
          item.labLoading = false
        } catch (error) {
          console.log(error)
          item.laboratoryList = []
        }
      }
    },
    // 改变周日是否上课
    async onChangeHaveClassSwitch (item) {
      let institute = item.institute
      if (institute && item.date.length > 0 && item.date[0] !== '' && item.date[1] !== '') {
        item.classroom = []
        try {
          item.laboratoryList = []
          item.labLoading = true
          item.laboratoryList = await this.getLabOptions(item)
          item.labLoading = false
        } catch (error) {
          item.laboratoryList = []
        }
      }
    },
    // 获取实验室列表
    async getLabOptions (timeItem) {
      timeItem.labLoading = true
      let request = {
        date: timeItem.date,
        haveClassOnWeekend: timeItem.haveClassOnWeekend
      }
      let institute = timeItem.institute
      let appCode = this.applyTraining.app_code
      try {
        let res = await getLabByDates(institute, appCode, request)
        res = res.data
        timeItem.labLoading = false
        if (res.code && res.data.length > 0) {
          return res.data
        } else {
          this.$Notice.error({
            title: res.code ? '提示' : '获取可用实验室列表失败',
            desc: res.code ? '该时间段下暂无可用实验室，请选择其他时间' : res.info
          })
          return []
        }
      } catch (error) {
        console.log(error)
        timeItem.labLoading = false
        return []
      }
    },
    // 新增实训项目
    add_exp_info () {
      let item = this.applyTraining.expBaseInfoItems[0]
      this.applyTraining.expBaseInfoItems.push({
        guid: generateGuid(),
        sid: this.applyTraining.expBaseInfoItems.length + 1,
        type: item.type,
        title: null,
        learntime: item.learntime,
        resources: item.resources,
        system: item.system,
        software: item.software,
        expTimeItems: [
          {
            guid: generateGuid(),
            institute: this.applyTraining.expBaseInfoItems[0].expTimeItems[0].institute,
            date: ['', ''],
            haveClassOnWeekend: false,
            classroom: null,
            laboratoryList: [],
            labLoading: false
          }
        ]
      })
      this.$nextTick(() => {
        // 跳转到对应的锚点
        location.hash = '#exp_item_' + this.applyTraining.expBaseInfoItems.length
      })
    },
    // 删除实验项目
    remove_exp_info (item, index) {
      let items = this.applyTraining.expBaseInfoItems
      if (items.indexOf(item) !== -1) {
        items.splice(index, 1)
      }
      this.$nextTick(() => {
        document.querySelector(`a[data-href='#exp_item_${index === 0 ? 1 : index}']`).click()
      })
    },
    // 提交表单
    async handleSubmit (name) {
      this.$refs[name].validate(async (valid) => {
        if (valid) {
          this.loading.submit = true
          this.showSpinWithTip('提交申请表中，请稍等...')
          let formData = JSON.parse(JSON.stringify(this.applyTraining, function (key, value) {
            if (key === 'guid' || key === 'laboratoryList' || key === 'labLoading' || key === 'major_loading' || key === 'major_options') {
              return undefined
            } else {
              return value
            }
          }))
          try {
            // 如果是修改则用修改的接口，不是则用新增的接口
            let response = this.isModified ? await editApply(JSON.stringify(formData)) : await submitApply(JSON.stringify(formData))
            this.$Spin.hide()
            let res = response.data
            if (res.code) {
              this.handleReset('applyTraining')
              if (this.isModified) {
                this.$emit('saveSuccess', true)
              } else {
                this.$Notice.success({
                  title: '成功',
                  desc: '成功提交实验室申请表。'
                })
              }
            } else {
              if (this.getElClass(res.data) === 'Array' && res.data.length > 0) {
                this.occupyData = []
                for (let i = 0; i < res.data.length; i++) {
                  for (let key in res.data[i]) {
                    if (res.data[i].hasOwnProperty(key)) {
                      let item = {
                        expIndex: i + 1,
                        date: key,
                        code: res.data[i][key].join('、')
                      }
                      this.occupyData.push(item)
                    }
                  }
                }
                this.modal = {
                  'show': true,
                  'title': res.info ? res.info : '抱歉，实验室使用时间冲突，请重新选择'
                }
              } else {
                this.$Notice.error({
                  title: '抱歉，提交失败',
                  desc: res.info
                })
              }
            }
          } catch (error) {
            this.$Spin.hide()
            console.log(error.stack)
            this.$Notice.error({
              title: '抱歉，提交失败',
              desc: error.stack
            })
          }
        } else {
          this.$Notice.error({
            title: '提交失败',
            desc: '抱歉，无法提交，请先完善表单信息再提交。'
          })
        }
      }, (err) => {
        console.log(err)
      }).catch(error => {
        console.log(error)
      })
      this.loading.submit = false
    },
    // 重置表单
    async handleReset (name) {
      let firstBaseGuid = this.applyTraining.expBaseInfoItems[0].guid || generateGuid()
      let oriData = {
        institute: this.applyTraining.institute,
        teacher_name: this.applyTraining.teacher_name,
        course_name: this.applyTraining.course_name
      }
      this.$refs[name].resetFields()
      this.applyTraining = {
        exp_type: 'TRAINING',
        app_code: this.isModified ? this.applyTraining.app_code : undefined,
        institute: this.isModified ? oriData.institute : this.$store.state.user.department,
        teacher_name: this.isModified ? oriData.teacher_name : this.$store.state.user.userName,
        course_name: this.isModified ? oriData.course_name : '',
        textbook: this.isModified ? oriData.teacher_name : null,
        classes: [{
          guid: generateGuid(),
          grade: null,
          major: null,
          major_options: []
        }],
        stu_num: null,
        expBaseInfoItems: [
          {
            guid: firstBaseGuid,
            sid: 1,
            type: '',
            title: null,
            learntime: null,
            resources: null,
            system: null,
            software: null,
            expTimeItems: [
              {
                guid: generateGuid(),
                institute: this.$store.state.user.department,
                date: ['', ''],
                haveClassOnWeekend: false,
                classroom: [],
                laboratoryList: [],
                labLoading: false
              }
            ]
          }
        ]
      }
      await this.$nextTick(() => {
        location.hash = 'course_info'
        localStorage.removeItem('applyTraining')
        localStorage.removeItem('t_courseOptions')
        localStorage.removeItem('t_classesOptions')
      })
    },
    // 通过从后台获取的数据填充到当前表单中，分为 修改 和 导入历史申请表两种情况
    async fillFormByData (data) {
      // 如果不是修改的话，就是导入历史申请表，把app_code删掉
      if (!this.isModified) {
        delete data.app_code
      } else {
        this.applyTraining.app_code = data.app_code
      }
      delete data.teacher_code
      delete data.course_code
      this.applyTraining.institute = data.institute
      this.historyLoading = true
      // 处理实训对象数据，要加上major_options，如果不加，后期再新增，会检测不到数据变化
      for (let i = 0; i < data.classes.length; i++) {
        let item = data.classes[i]
        item.guid = generateGuid()
        try {
          item.major_options = await this.getMajorOptions(item)
        } catch (error) {
          console.log(error)
          item.major_options = []
          this.$Notice.error({
            title: '获取专业列表失败，请稍后重试',
            desc: error.stack
          })
        }
        if (this.options.grade.indexOf(item.grade) < 0) {
          this.options.grade.push(item.grade)
        }
      }
      // 处理实验子项目数据
      for (let i = 0; i < data.expBaseInfoItems.length; i++) {
        const item = data.expBaseInfoItems[i]
        item.guid = generateGuid()
        item.sid = this.isModified ? item.sid : ''
        item.learntime = item.plan_hours
        item.expTimeItems = item.expTimeItemsTrain
        delete item.plan_hours
        delete item.actual_hours
        delete item.expTimeItemsCourse
        delete item.expTimeItemsTrain
        // 处理子实验的数据
        for (let j = 0; j < item.expTimeItems.length; j++) {
          const time = item.expTimeItems[j]
          time.guid = generateGuid()
          time.date = time.dates
          time.institute = time.classroom[0].institute
          time.laboratoryList = []
          time.labLoading = true
          // 获取 子实验 下的 子实验时间 的实验室列表
          try {
            time.laboratoryList = await this.getLabOptions(time)
          } catch (error) {
            console.log(error)
            this.$Notice.error({
              title: '获取可选实验室列表失败',
              desc: error
            })
            time.laboratoryList = []
          }
          if (this.isModified) {
            time.classroom = time.classroom.map(item => {
              return item.code
            })
          } else {
            time.classroom = []
          }
          delete time.labCodes
          delete time.dates
        }
      }
      this.$nextTick(() => {
        this.applyTraining = data
        this.historyLoading = false
        this.isFilledFormByData = true
        if (!this.loading.institute) {
          this.$Spin.hide()
        }
      })
    },
    // 显示带文字提示的Spin
    showSpinWithTip (tip) {
      this.$Spin.show({
        render: (h) => {
          return h('div', {'class': 'ivu-spin-large'}, [
            h('span', {
              'class': 'ivu-spin-dot',
              style: {
                display: 'inline-block'
              }
            }),
            h('div', tip)
          ])
        }
      })
    },
    leave (el, done) {
      Velocity(el, {
        scale: 1,
        backgroundColorRed: 250,
        backgroundColorGreen: 220,
        backgroundColorBlue: 174,
        backgroundColorAlpha: 0.87
      }, {
        duration: 300,
        easing: 'linear'
      })
      Velocity(el, {
        scale: 0.6
      }, {
        duration: 0,
        easing: 'ease'
      })
      Velocity(el, {
        scale: 0,
        height: 0,
        opacity: 0
      }, {
        duration: 500,
        easing: 'ease',
        complete: done
      })
    },
    /**
     * 利用MutationObserver实现监听元素class的变化
     */
    startMutationObserver () {
      let MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver
      let element = document.querySelector('.form-wrapper')
      this.observer = new MutationObserver(mutations => {
        for (let mutation of mutations) {
          if (mutation.type === 'attributes' && mutation.attributeName === 'class' && mutation.target.className.split(' ').indexOf('ivu-form-item') > -1) {
            // 高亮显示有错误的课程基本信息
            if (document.querySelector('#course_info').querySelectorAll('.ivu-form-item-error').length > 0) {
              document.querySelector("a[href='#course_info']") && document.querySelector("a[href='#course_info']").classList.add('text-danger')
            } else {
              document.querySelector("a[href='#course_info']") && document.querySelector("a[href='#course_info']").classList.remove('text-danger')
            }
            // 高亮显示有错误的实验项目
            document.querySelectorAll('.list-complete-item').forEach(expItem => {
              if (expItem.querySelectorAll('.ivu-form-item-error').length > 0) {
                if (document.querySelector('.ivu-anchor').querySelector("a[href='#" + expItem.id + "']")) {
                  document.querySelector('.ivu-anchor').querySelector("a[href='#" + expItem.id + "']").classList.add('text-danger')
                }
              } else {
                let el = document.querySelector('.ivu-anchor').querySelector("a[href='#" + expItem.id + "']")
                if (el) {
                  el.classList.remove('text-danger')
                }
              }
            })
          }
        }
      })
      this.observer.observe(element, {
        attributes: true,
        attributeFilter: ['class'],
        attributeOldValue: true,
        subtree: true,
        childList: true
      })
    },
    getElClass (o) {
      if (o === null) return 'Null'
      if (o === undefined) return 'undefined'
      return Object.prototype.toString.call(o).slice(8, -1)
    },
    isWeekend (date) {
      let start = new Date(date[0])
      let end = new Date(date[1])
      // 前后日相差期是否小于两天
      let differ = Date.parse(end) - Date.parse(start)
      let isLessOrEqualTwoDay = differ <= 86400000
      // 获取星期几，0 ~ 6 分别对应 周日到周六
      let week = {
        start: start.getDay(),
        end: end.getDay()
      }
      // 判断是不是 同一天周六/周日，或者是周六周日两天
      let isSatOrSun = ((week.start === 6 && week.end === 6) || (week.start === 0 && week.end === 0) || (week.start === 6 && week.end === 0))
      return isSatOrSun && isLessOrEqualTwoDay
    }
  },
  watch: {
    // 监听applyTraining数据的变化，如果发生改变则保存到localStorage
    applyTraining: {
      handler: function (val, oldVal) {
        if (!this.isModified) {
          localStorage.setItem('applyTraining', JSON.stringify(val))
        }
      },
      deep: true
    },
    'loading.submit': function (val, oldVal) {
      this.$emit('update:submitLoading', val)
    },
    pdfData: {
      async handler (val, oldVal) {
        let access = this.$store.state.user.access
        if (this.options.institute.indexOf(val.institute) < 0) {
          this.$emit('hide-spin')
          this.$Notice.error({
            title: '上传失败',
            desc: `抱歉，该教学大纲的 ${val.institute} 不存在，请重新上传其他教学大纲。`
          })
          return false
        }
        if (val.institute !== this.$store.state.user.department && access.indexOf('ROLE_SCHOOL_ADMIN') < 0 && access.indexOf('ROLE_ROOT') < 0) {
          this.$emit('hide-spin')
          this.$Notice.error({
            title: '上传失败',
            desc: access.indexOf('ROLE_INSTITUTE_ADMIN') > 0 ? '抱歉，只能上传开课院系为本学院的教学大纲' : '抱歉，只能上传本人的教学大纲'
          })
          return false
        }
        if (val.teacher_name === this.$store.state.user.userName || access.indexOf('ROLE_INSTITUTE_ADMIN') > 0) {
          await this.handleReset('applyTraining')
          this.applyTraining.teacher_name = val.teacher_name
          this.course_name = val.course_name
          this.applyTraining.textbook = val.textbook
          // 赋值第一个元素
          this.applyTraining.expBaseInfoItems[0].sid = val.expBaseInfoItems[0].sid
          this.applyTraining.expBaseInfoItems[0].type = val.expBaseInfoItems[0].type
          this.applyTraining.expBaseInfoItems[0].title = val.expBaseInfoItems[0].title
          this.applyTraining.expBaseInfoItems[0].learntime = val.expBaseInfoItems[0].learntime
          this.applyTraining.expBaseInfoItems[0].classroom = val.expBaseInfoItems[0].classroom
          this.applyTraining.expBaseInfoItems[0].expTimeItems = val.expBaseInfoItems[0].expTimeItems
          val.expBaseInfoItems.splice(0, 1)
          this.applyTraining.expBaseInfoItems.push(...JSON.parse(JSON.stringify(val.expBaseInfoItems)))
          setTimeout(() => {
            this.$emit('hide-spin')
          }, 1000)
        } else {
          this.$emit('hide-spin')
          this.$Notice.error({
            title: '上传失败',
            desc: '抱歉，只能上传任课教师为本人的教学大纲'
          })
        }
      }
      // ,deep: true
    }
  },
  computed: {
    isFillInstitute: function () {
      return !!this.applyTraining.institute
    }
  }
}
</script>
